﻿//
// Author: rgy
// Date: 2016-03-18 09:23:00
//

using UnityEngine;
using System.Collections.Generic;
using SoarD.Tween;
using UnityEngine.UI;

public class SoarDTween : MonoBehaviour
{
    private static SoarDTween _instance;
    private static uint m_counter = 0;

    private static uint Counter
    {
        get
        {
            m_counter++;
            if (m_counter > uint.MaxValue - 1)
            {
                m_counter = 1;
            }
            return m_counter;
        }
    }

    public delegate Vector2 PositionDelegate(float y);
    public delegate float AlphaDelegate(float y);
    private List<SoarDImplement> _tweens = new List<SoarDImplement>();

    public TweenObjectPool<TweenRtPosObj> TweenRtPosPool = new TweenObjectPool<TweenRtPosObj>();
    public TweenObjectPool<TweenSliderObj> TweenSliderPool = new TweenObjectPool<TweenSliderObj>();
    public TweenObjectPool<SoarDImplement> ImplementPool = new TweenObjectPool<SoarDImplement>();

    /// <summary>
    /// 获取实例
    /// 断言_instance不为空。(随游戏启动)
    /// </summary>
    public static SoarDTween Instance
    {
        get
        {
            if (_instance == null)
                Init();
            return _instance;
        }
    }

    public static void Init()
    {
        if (_instance == null)
        {
            GameObject go = new GameObject("~SoarDTween");
            _instance = go.AddComponent<SoarDTween>();
            m_counter = 0;
            DontDestroyOnLoad(go);
        }
    }

    private static SoarDImplement CreateImplement(TweenObjectBase itween)
    {
        Init();
        SoarDImplement imp = _instance.ImplementPool.Create().Init(Counter, itween);
        _instance._tweens.Add(imp);
        return imp;
    }

    // spline move
    public static SoarDImplement FuncMove(RectTransform rt, float targetY, float time, PositionDelegate posResult, SoarDTween.AlphaDelegate alphaResult)
    {
        TweenObjectBase itween = TweenFuncPosObj.Create(rt, targetY, time, posResult, alphaResult);
        return CreateImplement(itween);
    }

    // Move (World Position)
    public static SoarDImplement Move(GameObject gameObject, Vector3 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateMove(gameObject, target, time);
        return CreateImplement(itween);
    }

    // Move (LocalPosition)
    public static SoarDImplement MoveLocal(GameObject gameObject, Vector3 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateMoveLocal(gameObject, target, time);
        return CreateImplement(itween);
    }

    // Move And Look At (LocalPosition)
    public static SoarDImplement MoveLocalLookAt(GameObject gameObject, Vector3 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateMoveLocalLookAt(gameObject, target, time);
        return CreateImplement(itween);
    }

    // Move (LocalPosition X)
    public static SoarDImplement MoveLocalX(GameObject gameObject, float target, float time)
    {
        Vector3 targetV3 = gameObject.transform.localPosition;
        targetV3.x = target;
        TweenObjectBase itween = TweenRtPosObj.CreateMoveLocal(gameObject, targetV3, time);
        return CreateImplement(itween);
    }

    // Move (LocalPosition Y)
    public static SoarDImplement MoveLocalY(GameObject gameObject, float target, float time)
    {
        Vector3 targetV3 = gameObject.transform.localPosition;
        targetV3.y = target;
        TweenObjectBase itween = TweenRtPosObj.CreateMoveLocal(gameObject, targetV3, time);
        return CreateImplement(itween);
    }

    // Move (LocalPosition Z)
    public static SoarDImplement MoveLocalZ(GameObject gameObject, float target, float time)
    {
        Vector3 targetV3 = gameObject.transform.localPosition;
        targetV3.z = target;
        TweenObjectBase itween = TweenRtPosObj.CreateMoveLocal(gameObject, targetV3, time);
        return CreateImplement(itween);
    }

    // Move (UI)
    public static SoarDImplement Move(RectTransform rt, Vector2 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateMove(rt, target, time);
        return CreateImplement(itween);
    }

    // Move X(UI)
    public static SoarDImplement MoveX(RectTransform rt, float x, float time)
    {
        Vector2 target = new Vector2(x, rt.anchoredPosition.y);
        return Move(rt, target, time);
    }

    // Move Y(UI)
    public static SoarDImplement MoveY(RectTransform rt, float y, float time)
    {
        Vector2 target = new Vector2(rt.anchoredPosition.x, y);
        return Move(rt, target, time);
    }

    // Scale
    public static SoarDImplement Scale(Transform rt, Vector3 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateScale(rt, target, time);
        return CreateImplement(itween);
    }

    // Scale
    public static SoarDImplement Scale(GameObject go, Vector3 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateScale(go.transform, target, time);
        return CreateImplement(itween);
    }

    // Rotate
    public static SoarDImplement Rotate(Transform rt, Vector3 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateRotate(rt, target, time, false);
        return CreateImplement(itween);
    }

    // Rotate
    public static SoarDImplement Rotate(GameObject go, Vector3 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateRotate(go.transform, target, time, false);
        return CreateImplement(itween);
    }

    // Rotate
    public static SoarDImplement RotateMinAngle(GameObject go, Vector3 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateRotate(go.transform, target, time, true);
        return CreateImplement(itween);
    }

    // Rotate
    public static SoarDImplement RotateLocal(Transform rt, Vector3 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateRotateLocal(rt, target, time, false);
        return CreateImplement(itween);
    }

    // Rotate
    public static SoarDImplement RotateLocal(GameObject go, Vector3 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateRotateLocal(go.transform, target, time, false);
        return CreateImplement(itween);
    }

    // RotateX
    public static SoarDImplement RotateLocalX(GameObject go, float x, float time)
    {
        var euler = go.transform.localEulerAngles;
        Vector2 target = new Vector3(x, euler.y, euler.z);
        TweenObjectBase itween = TweenRtPosObj.CreateRotateLocal(go.transform, target, time, false);
        return CreateImplement(itween);
    }

    // RotateY
    public static SoarDImplement RotateLocalY(GameObject go, float y, float time)
    {
        var euler = go.transform.localEulerAngles;
        Vector2 target = new Vector3(euler.x, y, euler.z);
        TweenObjectBase itween = TweenRtPosObj.CreateRotateLocal(go.transform, target, time, false);
        return CreateImplement(itween);
    }

    //RotateLocal Auto Min
    public static SoarDImplement RotateLocalMinAngle(GameObject go, Vector3 target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateRotateLocal(go.transform, target, time, true);
        return CreateImplement(itween);
    }

    // Graphic Alpha
    public static SoarDImplement Alpha(Graphic render, float target, float time)
    {
        Color targetColor = render.color;
        targetColor.a = target;
        TweenObjectBase itween = TweenRtPosObj.CreateColor(render, targetColor, time);
        return CreateImplement(itween);
    }

    // SpriteRenderer Alpha
    public static SoarDImplement Alpha(SpriteRenderer render, float target, float time)
    {
        Color targetColor = render.color;
        targetColor.a = target;
        TweenObjectBase itween = TweenRtPosObj.CreateColor(render, targetColor, time);
        return CreateImplement(itween);
    }

    // Graphic Color
    public static SoarDImplement Color(Graphic graphic, Color target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateColor(graphic, target, time);
        return CreateImplement(itween);
    }

    // SpriteRenderer Color
    public static SoarDImplement Color(SpriteRenderer graphic, Color target, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateColor(graphic, target, time);
        return CreateImplement(itween);
    }

    // 文本跳动
    public static SoarDImplement JumpVal(Text text, double startVal, double targetVal, float time)
    {
        TweenObjectBase itween = TweenJumpObj.Create(text, startVal, targetVal, time);
        return CreateImplement(itween);
    }

    // slider移动(直接到目标值)
    public static SoarDImplement SliderMove(Slider slider, float targetVal, float time)
    {
        TweenObjectBase itween = TweenSliderObj.Create(slider, targetVal, time);
        return CreateImplement(itween);
    }

    // slider移动(先到终点)
    public static SoarDImplement SliderMoveDirect(Slider slider, float targetVal, float time, bool direct)
    {
        TweenObjectBase itween = TweenSliderDirectObj.Create(slider, targetVal, time, direct);
        return CreateImplement(itween);
    }

    // Image Fill Amount
    public static SoarDImplement ImageFillAmount(Image image, float targetVal, float time)
    {
        TweenObjectBase itween = TweenSliderObj.Create(image, targetVal, time);
        return CreateImplement(itween);
    }
    // RectTransform Size
    public static SoarDImplement CreateSizeDelta(RectTransform rectTrans, Vector3 targetVal, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateSizeDelta(rectTrans, targetVal, time);
        return CreateImplement(itween);
    }
    // RectTransform SizeX
    public static SoarDImplement CreateSizeDeltaX(RectTransform rectTrans, float x, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateSizeDeltaX(rectTrans, x, time);
        return CreateImplement(itween);
    }
    // RectTransform SizeY
    public static SoarDImplement CreateSizeDeltaY(RectTransform rectTrans, float y, float time)
    {
        TweenObjectBase itween = TweenRtPosObj.CreateSizeDeltaY(rectTrans, y, time);
        return CreateImplement(itween);
    }

    public static SoarDImplement CrystalTween(Transform transform, float rotateYSpeed, float targetPosY, float time)
    {
        TweenObjectBase itween = TweenCrystalObj.Create(transform, rotateYSpeed, targetPosY, time);
        return CreateImplement(itween);
    }

    public static float closestRot(float from, float to)
    {
        float minusWhole = 0 - (360 - to);
        float plusWhole = 360 + to;
        float toDiffAbs = Mathf.Abs(to - from);
        float minusDiff = Mathf.Abs(minusWhole - from);
        float plusDiff = Mathf.Abs(plusWhole - from);
        if (toDiffAbs < minusDiff && toDiffAbs < plusDiff)
        {
            return to;
        }
        else {
            if (minusDiff < plusDiff)
            {
                return minusWhole;
            }
            else {
                return plusWhole;
            }
        }
    }

    void Update()
    {
        for (int i = _tweens.Count - 1; i >= 0; i--)
        {
            if (_tweens[i].IsDestroy)
            {
                _tweens[i].Destroy();
                _tweens.RemoveAt(i);
                continue;
            }
            _tweens[i].Excute(Time.deltaTime);
        }
    }

    public static void Cancel(uint id)
    {
        if (id <= 0) return;
        for (int i = 0; i < Instance._tweens.Count; i++)
        {
            if (Instance._tweens[i].id == id)
            {
                Instance._tweens[i].SDCancel();
            }
        }
    }

    public static void Cancel(GameObject gameObject)
    {
        if (_instance == null || gameObject == null) return;
        for (int i = 0; i < Instance._tweens.Count; i++)
        {
            if (Instance._tweens[i].gameObject == gameObject)
            {
                Instance._tweens[i].SDCancel();
            }
        }
    }

    public static void Pause(uint id)
    {
        for (int i = 0; i < Instance._tweens.Count; i++)
        {
            if (Instance._tweens[i].id == id)
            {
                Instance._tweens[i].Pause();
            }
        }
    }

    public static void Resume(uint id)
    {
        for (int i = 0; i < Instance._tweens.Count; i++)
        {
            if (Instance._tweens[i].id == id)
            {
                Instance._tweens[i].Resume();
            }
        }
    }
}